﻿using System;
using IocPerformance.Classes.Complex;
using IocPerformance.Classes.Conditions;
using IocPerformance.Classes.Dummy;
using IocPerformance.Classes.Generics;
using IocPerformance.Classes.Multiple;
using IocPerformance.Classes.Standard;
using MugenInjection;

namespace IocPerformance.Adapters
{
    public sealed class MugenContainerAdapter : ContainerAdapterBase
    {
        private MugenInjector container;

        public override string PackageName
        {
            get { return "MugenInjection"; }
        }

        public override bool SupportsConditional
        {
            get { return false; }
        }

        public override bool SupportGeneric
        {
            get { return true; }
        }

        public override bool SupportsMultiple
        {
            get { return true; }
        }

        public override bool SupportsInterception
        {
            get { return false; }
        }

        public override object Resolve(Type type)
        {
            return this.container.Get(type);
        }

        public override TService Resolve<TService>()
        {
            return container.Get<TService>();
        }

        public override void Dispose()
        {
            // Allow the container and everything it references to be disposed.
            this.container = null;
        }

        public override void Prepare()
        {
            this.container = new MugenInjector();

            this.RegisterDummies();
            this.RegisterStandard();
            this.RegisterComplex();
            this.RegisterMultiple();
            this.RegisterOpenGeneric();
            this.RegisterConditional();
            //this.RegisterInterceptor();
        }

        private void RegisterDummies()
        {
            this.container.Bind<IDummyOne>().To<DummyOne>().InTransientScope();
            this.container.Bind<IDummyTwo>().To<DummyTwo>().InTransientScope();
            this.container.Bind<IDummyThree>().To<DummyThree>().InTransientScope();
            this.container.Bind<IDummyFour>().To<DummyFour>().InTransientScope();
            this.container.Bind<IDummyFive>().To<DummyFive>().InTransientScope();
            this.container.Bind<IDummySix>().To<DummySix>().InTransientScope();
            this.container.Bind<IDummySeven>().To<DummySeven>().InTransientScope();
            this.container.Bind<IDummyEight>().To<DummyEight>().InTransientScope();
            this.container.Bind<IDummyNine>().To<DummyNine>().InTransientScope();
            this.container.Bind<IDummyTen>().To<DummyTen>().InTransientScope();
        }

        private void RegisterStandard()
        {
            this.container.Bind<ISingleton>().To<Singleton>().InSingletonScope();
            this.container.Bind<ITransient>().To<Transient>().InTransientScope();
            this.container.Bind<ICombined>().To<Combined>().InTransientScope();
        }

        private void RegisterComplex()
        {
            this.container.Bind<IFirstService>().To<FirstService>().InSingletonScope();
            this.container.Bind<ISecondService>().To<SecondService>().InSingletonScope();
            this.container.Bind<IThirdService>().To<ThirdService>().InSingletonScope();
            this.container.Bind<ISubObjectOne>().To<SubObjectOne>().InTransientScope();
            this.container.Bind<ISubObjectTwo>().To<SubObjectTwo>().InTransientScope();
            this.container.Bind<ISubObjectThree>().To<SubObjectThree>().InTransientScope();
            this.container.Bind<IComplex>().To<Complex>().InTransientScope();
        }

        private void RegisterConditional()
        {
            // conditional export
            container.Bind<ImportConditionObject>().To<ImportConditionObject>().InTransientScope();
            container.Bind<ImportConditionObject2>().To<ImportConditionObject2>().InTransientScope();
            container.Bind<IExportConditionInterface>()
                     .To<ExportConditionalObject>()
                     .WhenIntoIsAssignable<ImportConditionObject>()
                     .InTransientScope();
            container.Bind<IExportConditionInterface>()
                     .To<ExportConditionalObject2>()
                     .WhenIntoIsAssignable<ImportConditionObject2>()
                     .InTransientScope();
        }

        private void RegisterOpenGeneric()
        {
            // generic export
            container.Bind(typeof(IGenericInterface<>)).To(typeof(GenericExport<>)).InTransientScope();
            container.Bind(typeof(ImportGeneric<>)).To(typeof(ImportGeneric<>)).InTransientScope();
        }

        private void RegisterMultiple()
        {
            // multiple exports
            container.Bind<ISimpleAdapter>().To<SimpleAdapterOne>().InTransientScope();
            container.Bind<ISimpleAdapter>().To<SimpleAdapterTwo>().InTransientScope();
            container.Bind<ISimpleAdapter>().To<SimpleAdapterThree>().InTransientScope();
            container.Bind<ISimpleAdapter>().To<SimpleAdapterFour>().InTransientScope();
            container.Bind<ISimpleAdapter>().To<SimpleAdapterFive>().InTransientScope();

            container.Bind<ImportMultiple>().To<ImportMultiple>().InTransientScope();
        }

        //private void RegisterInterceptor()
        //{
        //    this.container.Bind<ICalculator>().To<Calculator>().InTransientScope().InterceptAsTarget(new MugenInjectionInterceptionLogger());
        //}
    }
}